from collections.abc import AsyncGenerator

from litestar.contrib.sqlalchemy.base import UUIDBase
from litestar.contrib.sqlalchemy.plugins import (
    AsyncSessionConfig,
    EngineConfig,
    SQLAlchemyAsyncConfig,
)
from litestar.exceptions import ClientException
from litestar.status_codes import HTTP_409_CONFLICT
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession

from config.setting import CONFIG

# sessionmaker = async_sessionmaker(expire_on_commit=False)


# @asynccontextmanager
# async def db_connection(app: Litestar):
#     """
#     连接数据库
#     """
#     engine = getattr(app.state, "engine", None)
#     if engine is None:
#         # postgresql+asyncpg://user:password@host:port/dbname
#         engine = create_async_engine(
#             "postgresql+asyncpg://{username}:{password}@{host}:{port}/{database}".format(
#                 username=db_config["username"],
#                 password=db_config["password"],
#                 host=db_config["host"],
#                 port=db_config["port"],
#                 database=db_config["database"],
#             ),
#             echo=db_config["echo"],
#         )
#         app.state.engine = engine

#     async with engine.begin() as conn:
#         await conn.run_sync(Base.metadata.create_all)

#     try:
#         yield
#     finally:
#         await engine.dispose()


# async def provide_db_session(state: State):
#     """
#     提供 Sqlalchemy Session
#     """
#     async with sessionmaker(bind=state.engine) as session:
#         try:
#             async with session.begin():
#                 yield session
#         except IntegrityError as e:
#             raise ClientException(
#                 status_code=HTTP_409_CONFLICT,
#                 detail=str(e),
#             ) from e

# 获取数据库配置
db_config = CONFIG["db"]

# session 配置
session_config = AsyncSessionConfig(expire_on_commit=False)

# engine 配置
engine_config = EngineConfig(
    echo=db_config["echo"],
    pool_size=db_config["pool_size"],
    max_overflow=db_config["max_overflow"],
    pool_timeout=db_config["pool_timeout"],
    pool_recycle=db_config["pool_recycle"],
)

# sqlalchemy 配置
sqlalchemy_config = SQLAlchemyAsyncConfig(
    connection_string="postgresql+asyncpg://{username}:{password}@{host}:{port}/{database}".format(
        username=db_config["username"],
        password=db_config["password"],
        host=db_config["host"],
        port=db_config["port"],
        database=db_config["database"],
    ),
    metadata=UUIDBase.metadata,
    create_all=True,
    session_config=session_config,
    engine_config=engine_config,  # type: ignore
)


# 提供 Transaction
async def provide_transaction(
    db_session: AsyncSession,
) -> AsyncGenerator[AsyncSession, None]:
    try:
        async with db_session.begin():
            yield db_session
    except IntegrityError as exc:
        raise ClientException(
            status_code=HTTP_409_CONFLICT,
            detail="Duplicate key of the entry",
        ) from exc
